#ifdef ECOS
#include "stdio.h"
#include "stdlib.h"
#include "drv_api.h"
#else
#include <stdio.h>
#include <string.h>
#endif
#include "AtapiReg.h"
#include "DmacReg.h"
#include "Atapi.h"

//------------------------------------------------------------------------
//  Host read data from HD using DMA/UDMA 48-bit LBA command
//
//  In : drive_no : 0: master    1: slave
//	     DMAstartaddr : DMA starting address (non-cacheable)
//	     startLBA : starting LBA (bit 0-31)
//       count : number of sectors
//
//  Ret: 0 : fail
//       1 : success
//------------------------------------------------------------------------
int atapiReadDMA(UCHAR drive_no, UINT32 DMAstartaddr, UINT32 startLBA,  USHORT count)
{
    UINT32 loop, uStatus, startLBA_H=0,uEnterToTransferDataState = FALSE;
    UINT32 VirtualAddr, PhysicalAddr;
    UINT32 PADTable[32][2];   //(256-1)/8+1

    if (gScatterGather==1)
    { 
       outpw(DMAC_CSR, DMAC_CR_DMACEN | DMAC_CR_SG_EN);    
       outpw(DMAC_SAR1, (UINT32)PADTable);

       VirtualAddr=DMAstartaddr;
       for (loop=0;loop<(count-1)/8+1;loop++)
       {
         PhysicalAddr=sysGetPhyPageAddr(VirtualAddr);
         PADTable[loop][0]=PhysicalAddr;
         
         if (loop==(count-1)/8)
             PADTable[loop][1]=(count % 8) | 0x80000000;         
         else
             PADTable[loop][1]=8;         
         VirtualAddr+=4096;         
       }
       sysFlushCache(D_CACHE);
     }
     else
     {
        // Set DMA Transfer Starting Address
        outpw(DMAC_CSR, DMAC_CR_DMACEN);    
        outpw(DMAC_SAR1, DMAstartaddr);
     }
	
    // Total sectors to be transfer 
    outpw(ATAPI_SECCNT, count);

    // Prepare parameter 
    if (!atapi_wait_BSY() )	 
        return 0;
    if (!atapi_wait_DRQ(0))
        return 0;

    if ((IDE_HEADER_INFO[drive_no].command_set_support & 0x0400))    // 48 bit LBA
    	{
          ide_outp(ATAPI_ATA_SEC, count >> 8);                                // count 8-15 (previous)
          ide_outp(ATAPI_ATA_SEC, count & 0xFF);                             // count 0-7 (current)
          ide_outp(ATAPI_ATA_LBAH, ((startLBA_H & 0x0000FF00) >> 8));   // LBA 40-47
          ide_outp(ATAPI_ATA_LBAH, ((startLBA & 0x00FF0000) >> 16));  // LBA 16-23     
          ide_outp(ATAPI_ATA_LBAM, (startLBA_H & 0x000000FF));              // LBA 32-39
          ide_outp(ATAPI_ATA_LBAM, ((startLBA & 0x0000FF00) >> 8));   // LBA 8-15  
          ide_outp(ATAPI_ATA_LBAL, ((startLBA & 0xFF000000) >> 24));  // LBA 24-31
          ide_outp(ATAPI_ATA_LBAL, (startLBA & 0x000000FF));               // LBA 0-7
          ide_outp(ATAPI_ATA_DEVH, ((drive_no ? SLAVE_MODE : MASTER_MODE) | LBA_MODE));
	
           // READ (U)DMA Command 
          ide_outp(ATAPI_ATA_COMD, READ_DMA_EXT);
    	}
    else
    	{
          ide_outp(ATAPI_ATA_SEC, count);    
          ide_outp(ATAPI_ATA_LBAL, (startLBA& 0x000000FF)); 
          ide_outp(ATAPI_ATA_LBAM, ((startLBA & 0x0000FF00) >> 8));         
          ide_outp(ATAPI_ATA_LBAH, ((startLBA & 0x00FF0000) >> 16));
          ide_outp(ATAPI_ATA_DEVH, ((drive_no ? SLAVE_MODE : MASTER_MODE) | LBA_MODE
		                                  | ((startLBA & 0x0F000000) >> 24)));	
          // READ (U)DMA Command 
          ide_outp(ATAPI_ATA_COMD, READ_DMA);
    	}

    // Wait until (BSY = 0 & DRQ = 1 & DMARQ asserted) or 
    //   (BSY = 1 & DRQ = 0 & DMARQ asserted) 
    for(loop = 0; loop < ATAPI_DELAY_LOOP; loop++)
    {
        uStatus = ide_inp(ATAPI_ATA_STAT);
        if (((uStatus & 0x80) || (uStatus & 0x08)) && ((uStatus & 0x88) != 0x88))
            if (inpw(ATAPI_PINSTAT) & ATAPI_PINSTAT_DMARQ)
            {
                _atapi_DMARQ = FALSE;
                uEnterToTransferDataState = TRUE;
                break;
            }    
    }
    
    /* Check if the device enters transfer state */
    if (!uEnterToTransferDataState)
        return 0;
    
    if (gDMAtype==0)   // DMA mode
        outpw(ATAPI_DMACSR, ATAPI_DMACSR_DMAdir_IN |
                            ATAPI_DMACSR_EOSen |
                            ATAPI_DMACSR_DMAen);    
    else           // gDMAtype=1   UDMA
        outpw(ATAPI_DMACSR, ATAPI_DMACSR_DMAdir_IN |
                            ATAPI_DMACSR_EOSen |
                            ATAPI_DMACSR_UDMAen);    
    
    // Transfer accomplishes?     
    if (!atapi_wait_ENDOFSECTOR())     // Wait for ENDOFSECTOR = assert 
        return 0;
    if (!atapi_wait_INTRQ())
        return 0;
    
    // Clear flags     
    _atapi_DMARQ = _atapi_INTRQ = FALSE;
    
    // Polling DMATIP pin = 0, DMA complete
    if (!atapi_wait_DMATIP())
        return 0;
    
    // check HD's status 
    if (ide_inp(ATAPI_ATA_STAT) & 0x01)     
        return 0;
 
    return 1;

} 

//------------------------------------------------------------------------
//  Host write data to HD using 48-bit or 28-bit LBA DMA/UDMA command
//
//  In : drive_no : 0: master    1: slave
//	     DMAstartaddr : DMA starting address (non-cacheable)
//	     startLBA : starting LBA (bit 0-31) (sector)
//       count : number of sectors
//
//  Ret: 0 : fail
//       1 : success
//------------------------------------------------------------------------
int atapiWriteDMA(UCHAR drive_no, UINT32 DMAstartaddr, UINT32 startLBA,  USHORT count)
{
    UINT32     loop, uStatus, startLBA_H=0,uEnterToTransferDataState = FALSE;
 
    UINT32 VirtualAddr, PhysicalAddr;
    UINT32 PADTable[32][2];   //(256-1)/8+1

    if (gScatterGather==1)
    { 
       outpw(DMAC_CSR, DMAC_CR_DMACEN | DMAC_CR_SG_EN);    
       outpw(DMAC_SAR1, (UINT32)PADTable);

       VirtualAddr=DMAstartaddr;
       for (loop=0;loop<(count-1)/8+1;loop++)
       {
         PhysicalAddr=sysGetPhyPageAddr(VirtualAddr);
         PADTable[loop][0]=PhysicalAddr;
         
         if (loop==(count-1)/8)
             PADTable[loop][1]=(count % 8) | 0x80000000;         
         else
             PADTable[loop][1]=8;         
         VirtualAddr+=4096;         
       }
       sysFlushCache(D_CACHE);
    }
    else
    {
       // Set DMA Transfer Starting Address
       outpw(DMAC_CSR, DMAC_CR_DMACEN);    
       outpw(DMAC_SAR1, DMAstartaddr);
    }
   
    // Total sectors to be transfer 
    outpw(ATAPI_SECCNT, count);

    // prepare  parameter 
    if (!atapi_wait_BSY())	  
        return 0;
    if (!atapi_wait_DRQ(0))
        return 0;
	
    // Clear flags 
    _atapi_DMARQ = _atapi_INTRQ = FALSE;

    if ((IDE_HEADER_INFO[drive_no].command_set_support & 0x0400))    // 48 bit LBA
    	{
          ide_outp(ATAPI_ATA_SEC, count >> 8);                                // count 8-15 (previous)
          ide_outp(ATAPI_ATA_SEC, count & 0xFF);                             // count 0-7 (current)
          ide_outp(ATAPI_ATA_LBAH, ((startLBA_H & 0x0000FF00) >> 8));   // LBA 40-47
          ide_outp(ATAPI_ATA_LBAH, ((startLBA & 0x00FF0000) >> 16));  // LBA 16-23     
          ide_outp(ATAPI_ATA_LBAM, (startLBA_H & 0x000000FF));              // LBA 32-39
          ide_outp(ATAPI_ATA_LBAM, ((startLBA & 0x0000FF00) >> 8));   // LBA 8-15  
          ide_outp(ATAPI_ATA_LBAL, ((startLBA & 0xFF000000) >> 24));  // LBA 24-31
          ide_outp(ATAPI_ATA_LBAL, (startLBA & 0x000000FF));               // LBA 0-7
          ide_outp(ATAPI_ATA_DEVH, ((drive_no ? SLAVE_MODE : MASTER_MODE) | LBA_MODE));
	
           // WRITE (U)DMA Command 
          ide_outp(ATAPI_ATA_COMD, WRITE_DMA_EXT);
    	}
    else
    	{
          ide_outp(ATAPI_ATA_SEC, count);    
          ide_outp(ATAPI_ATA_LBAL, (startLBA& 0x000000FF)); 
          ide_outp(ATAPI_ATA_LBAM, ((startLBA & 0x0000FF00) >> 8));         
          ide_outp(ATAPI_ATA_LBAH, ((startLBA & 0x00FF0000) >> 16));
          ide_outp(ATAPI_ATA_DEVH, ((drive_no ? SLAVE_MODE : MASTER_MODE) | LBA_MODE
		                                  | ((startLBA & 0x0F000000) >> 24)));	
          // WRITE (U)DMA Command 
          ide_outp(ATAPI_ATA_COMD, WRITE_DMA);
    	}
    // Wait until (BSY = 0 & DRQ = 1 & DMARQ asserted) or 
    //              (BSY = 1 & DRQ = 0 & DMARQ asserted) 
    for(loop = 0; loop < ATAPI_DELAY_LOOP; loop++)
    {
        uStatus = ide_inp(ATAPI_ATA_STAT);
        if(((uStatus & 0x80) || (uStatus & 0x08)) && ((uStatus & 0x88) != 0x88))
            if(inpw(ATAPI_PINSTAT) & ATAPI_PINSTAT_DMARQ)
            {        
                _atapi_DMARQ = FALSE;
                uEnterToTransferDataState = TRUE;
                break;
            }    
    }
    
    if(!uEnterToTransferDataState)
        return 0;
    
    // Write data from host to device 
    if (gDMAtype==0)   // DMA mode
        outpw(ATAPI_DMACSR, ATAPI_DMACSR_DMAdir_OUT |
                            ATAPI_DMACSR_EOSen |
                            ATAPI_DMACSR_DMAen);    
    else           // gDMAtype=1   UDMA
        outpw(ATAPI_DMACSR, ATAPI_DMACSR_DMAdir_OUT |
                            ATAPI_DMACSR_EOSen |
                            ATAPI_DMACSR_UDMAen);                                    

    // Transfer accomplishes? 
    if (!atapi_wait_ENDOFSECTOR())     // Wait for ENDOFSECTOR = assert 
        return 0;
    if (!atapi_wait_INTRQ())
        return 0;
    
    // Clear flags  
    _atapi_DMARQ = _atapi_INTRQ = FALSE;
    
    // Polling DMATIP pin = 0, DMA complete
   if (!atapi_wait_DMATIP())
        return 0;
    
    // check HD's status
    if (ide_inp(ATAPI_ATA_STAT) & 0x01)     
        return 0;
   
    return 1;
} 
			
